package com.cbtx.networklib.factory

import com.cbtx.networklib.ContextManager
import com.cbtx.networklib.config.DefaultParamsConfig.keepAliveDuration
import com.cbtx.networklib.config.DefaultParamsConfig.maxIdleConnections
import com.cbtx.networklib.config.LogConfig
import com.cbtx.networklib.constant.ByteConstants.MB
import com.cbtx.networklib.cookie.CookieJarImpl
import com.cbtx.networklib.cookie.PersistentCookieStore
import com.cbtx.networklib.ssl.MyX509TrustManager
import com.cbtx.networklib.ssl.SSLManager
import okhttp3.Cache
import okhttp3.ConnectionPool
import okhttp3.Interceptor
import okhttp3.OkHttpClient
import retrofit2.CallAdapter
import retrofit2.Converter
import retrofit2.Retrofit
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.converter.scalars.ScalarsConverterFactory
import java.io.File
import java.util.ArrayList
import java.util.concurrent.TimeUnit

/**
 * author : joker.peng
 * e-mail : joker@fiture.com
 * date   : 2021/6/28 8:26 PM
 * desc   :
 */
class NetworkFactory<ApiService> {

    companion object {
        const val URL_EMPTY = "baseUrl is empty"
        const val API_EMPTY = "ApiService is null"
        const val CACHE_SIZE: Int = 20 * MB
    }

    private var builder: OkHttpClient.Builder? = null

    private var interceptors: ArrayList<Interceptor>? = null

    private var headerInterceptor: Interceptor? = null
    private var logInterceptor: Interceptor? = null
    private var isCacheEnable: Boolean? = null

    private var adapterFactory: CallAdapter.Factory? = null
    private var gsonConverterFactory: Converter.Factory? = null
    private var connectTimeout: Long? = null
    private var readTimeout: Long? = null
    private var cacheSize = 0
    private var cacheDirectory: File? = null
    private var baseUrl: String? = null

    private var apiService: Class<ApiService>? = null

    private var isOpenLog: Boolean = true
    private var level: LogConfig = LogConfig.BODY
    private var logTag: String = "MJ"
    private var isPrintPrettyJson = true

    /**
     * SSL 证书校验，默认关闭
     */
    private var isOpenSSLCheckValidity: Boolean = true

    /**
     * 参数检查
     */
    private fun checkRequiredParameters() {
        ExceptionFactory.checkParameterIsNotNull(baseUrl, URL_EMPTY)
        ExceptionFactory.checkParameterIsNotNull(apiService, API_EMPTY)
    }

    fun create(): ApiService {
        checkRequiredParameters()
        return create(getBuilder().build())
    }

    private fun create(okHttpClient: OkHttpClient): ApiService {
        val retrofit = Retrofit.Builder()
            .baseUrl(baseUrl)
            .client(okHttpClient)
            .addCallAdapterFactory(adapterFactory ?: RxJava2CallAdapterFactory.create())
            .addConverterFactory(ScalarsConverterFactory.create())
            .addConverterFactory(gsonConverterFactory ?: GsonConverterFactory.create())
            .build()
        return retrofit.create(apiService)
    }

    /**
     * 用自定义 OkHttpClient.Builder 去创建 OkHttpClient
     */
    fun setBuilder(builder: OkHttpClient.Builder): NetworkFactory<ApiService> {
        this.builder = builder
        return this
    }

    private fun addInterceptor(interceptors: ArrayList<Interceptor>): NetworkFactory<ApiService> {
        if (interceptors.size > 0) {
            this.interceptors?.addAll(interceptors)
        }
        return this
    }

    fun addInterceptor(vararg interceptors: Interceptor): NetworkFactory<ApiService> {
        if (this.interceptors == null) {
            this.interceptors = ArrayList()
        }
        if (interceptors != null && interceptors.isNotEmpty()) {
            this.interceptors?.addAll(listOf(*interceptors))
        }
        return this
    }

    /**
     * 设置连接超时时间，单位ms，默认 30000ms
     */
    fun setConnectTimeout(connectTimeout: Long): NetworkFactory<ApiService> {
        this.connectTimeout = connectTimeout
        return this
    }

    fun setReadTimeout(readTimeout: Long): NetworkFactory<ApiService> {
        this.readTimeout = readTimeout
        return this
    }

    /**
     * 是否开启ssl校验
     */
    fun setSSLCheckValidity(isOpenSSLCheckValidity: Boolean): NetworkFactory<ApiService> {
        this.isOpenSSLCheckValidity = isOpenSSLCheckValidity
        return this
    }

    /**
     * 批量添加自定义拦截器
     */
    fun addInterceptors(interceptors: ArrayList<Interceptor>): NetworkFactory<ApiService> {
        this.interceptors = interceptors
        return this
    }

    /**
     * 批量添加自定义拦截器
     */
    fun addLogInterceptor(logInterceptor: Interceptor): NetworkFactory<ApiService> {
        this.logInterceptor = logInterceptor
        return this
    }

    fun setBaseUrl(baseUrl: String): NetworkFactory<ApiService> {
        this.baseUrl = baseUrl
        return this
    }

    fun setApiService(api: Class<ApiService>): NetworkFactory<ApiService> {
        this.apiService = api
        return this
    }

    fun setCacheEnable(
        isCacheEnable: Boolean,
        cacheSize: Int = CACHE_SIZE,
        cacheDirectory: File = File(ContextManager.getContext().cacheDir, "httpCache")
    ): NetworkFactory<ApiService> {
        this.isCacheEnable = isCacheEnable
        this.cacheSize = cacheSize
        this.cacheDirectory = cacheDirectory
        return this
    }

    fun setLogLevel(
        isOpenLog: Boolean = true,
        level: LogConfig = LogConfig.BODY,
        logTag: String = "MJ"
    ): NetworkFactory<ApiService> {
        this.isOpenLog = isOpenLog
        this.level = level
        this.logTag = logTag
        return this
    }

    /**
     * 是否格式化打印请求日志
     */
    fun setPrettyJsonPrinting(isPrintPrettyJson: Boolean): NetworkFactory<ApiService> {
        this.isPrintPrettyJson = isPrintPrettyJson
        return this
    }

    /**
     * 初始化 OkHttpClientBuilder
     */
    private fun getBuilder(): OkHttpClient.Builder {

        // 此处使用自定义的 OkHttpClient.Builder
        if (builder == null) {// 没有自定义，则在库中创建
            builder = OkHttpClient.Builder()
                .cookieJar(CookieJarImpl(PersistentCookieStore(ContextManager.getContext())))
                .connectTimeout(connectTimeout ?: 3000 * 10L, TimeUnit.MILLISECONDS)
                .readTimeout(readTimeout ?: 3000 * 10L, TimeUnit.MILLISECONDS)
                .connectionPool(ConnectionPool(maxIdleConnections, keepAliveDuration, TimeUnit.SECONDS))

            // 添加忽略SSL时间校验
            if (!isOpenSSLCheckValidity) {
                builder!!.sslSocketFactory(SSLManager.getSSLSocketFactory(), MyX509TrustManager())
            }

            if (ContextManager.getContext() != null) {
                // 缓存
                isCacheEnable?.apply {
                    if (this) {
                        val cache = Cache(cacheDirectory!!, cacheSize.toLong())
                        builder!!.cache(cache)
                    }
                }
            }

            // 头信息拦截器
            headerInterceptor?.let { addInterceptor(it) }

            // 日志拦截器
            logInterceptor?.let {
                addInterceptor(it)
            }

            // 自定义拦截器
            interceptors?.forEach {
                builder!!.addInterceptor(it)
            }
        }
        return builder!!
    }

    /**
     * 初始化缓存配置
     */
    private fun setCacheConfig(builder: OkHttpClient.Builder) {

    }

}
